﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TextTemplating.VSHost;
using System.Runtime.InteropServices;
using System.IO;
using System.CodeDom.Compiler;
using System.Windows.Forms;
using System.Xml;

namespace CTX.CtxPackageVS2012
{
    [Serializable]
    [GuidAttribute("D80F9BE3-E1FD-47AA-8B1C-B9A16A0A50EF")]
    public class T4CommonTextTemplatingFileGenerator : BaseCodeGeneratorWithSite
    {
        #region Properties
        public string TemplatePath { get; private set; }
        public EnvDTE.ProjectItem CurrentProjectItem { get; set; }
        #endregion

        #region Ctors

        public T4CommonTextTemplatingFileGenerator()
        {
            TemplatePath = Configurations.Settings["BaseTemplatePath"] ?? Path.Combine(Configurations.CurrentPath, "Templates");
        }

        #endregion
        
        #region Generate Code

        protected string GenerateCode(EnvDTE.ProjectItem projectItem)
        {
            var namespaceSuggestion = GetNamespaceSuggestion(projectItem);
            var templateFileFullName = GetTemplateFileFullName(projectItem);
            var inputDataFilename = projectItem.FileNames[1];

            var host = new CommonTextTemplatingEngineHost();
            var engine = new Microsoft.VisualStudio.TextTemplating.Engine();
            host.CurrentProjectItem = projectItem;
            host.TemplateFile = templateFileFullName;
            host.NamespaceSuggestion = namespaceSuggestion; 

            //Read the text template
            string input = File.ReadAllText(templateFileFullName);

            input = input.Replace("$inputDataFilename$", inputDataFilename);
            input = input.Replace("$namespace$", namespaceSuggestion); 
           

            //return NamespaceSuggestion +"  "+ edmxDataFilename;
            //Transform the text template

            string output = engine.ProcessTemplate(input, host);
            if (host.Errors != null && host.Errors.Count > 0)
            {
                output += "//" + inputDataFilename + Environment.NewLine;
                output += "//" + namespaceSuggestion + Environment.NewLine;

                foreach (CompilerError error in host.Errors)
                {
                    output += Environment.NewLine + error.ErrorText;
                }
            } 

            return output;
        }
        #endregion

        #region Implement BaseCodeGeneratorWithSite abstract methods

        protected override byte[] GenerateCode(string inputFileName, string inputFileContent)
        {
            var projectItem = GetService(typeof(EnvDTE.ProjectItem)) as EnvDTE.ProjectItem;
            var templateFileContent = String.Empty;
            var templateEncoding = Encoding.UTF8;
            CurrentProjectItem = projectItem;
            templateFileContent = GenerateCode(projectItem);
            return templateEncoding.GetBytes(templateFileContent); 
        }
        

        public override string GetDefaultExtension()
        {
            return GetExtension(CurrentProjectItem);
        }

        public string GetExtension(EnvDTE.ProjectItem projectItem)
        {
            if (projectItem == null)
                return ".cs";
            var inputDataFilename = projectItem.FileNames[1];
            return Configurations.ExtensionsMapping[Path.GetExtension(inputDataFilename)] ?? ".cs";
        }

        #endregion

        #region Other Methods
         
        private string GetNamespaceSuggestion(EnvDTE.ProjectItem projectItem)
        {
            return projectItem.ContainingProject.Name +"." + Path.GetFileNameWithoutExtension(projectItem.Name);
        }

        private string GetTemplateFileFullName(EnvDTE.ProjectItem projectItem)
        {
            var projectItemExtension = Path.GetExtension(projectItem.FileNames[0]);
            var projectItemFileName = Path.GetFileName(projectItem.Name).ToLowerInvariant();

            var templateFileName = Configurations.TemplatesMapping[projectItemFileName];
            if (string.IsNullOrEmpty(templateFileName))
            {
                templateFileName = Configurations.TemplatesMapping[projectItemExtension];
            }
            if (string.IsNullOrEmpty(templateFileName))
            {
                templateFileName = Configurations.TemplatesMapping["DefaultTemplateFileName"];
            }
            templateFileName = templateFileName ?? "Template.tt";
            return Path.Combine(TemplatePath, templateFileName);
        }
        #endregion
    }
}
